import 抽象语法树节点.*;
import 抽象语法树节点.表达式类.加法表达式;
import 抽象语法树节点.表达式类.变量引用表达式;
import 抽象语法树节点.表达式类.整数字面量表达式;
import 抽象语法树节点.表达式类.方法调用表达式;
import 抽象语法树节点.语句类.变量定义语句;
import 抽象语法树节点.语句类.块语句;
import 抽象语法树节点.语句类.赋值语句;

// 用于生成抽象语法树
public class 抽象语法树访问器 extends CymbolBaseVisitor<抽象语法树> {

    @Override
    public 抽象语法树 visitCompilationUnit(CymbolParser.CompilationUnitContext ctx) {
        var 节点 = new 抽象语法树[ctx.children.size()];

        for (var i = 0; i < 节点.length; i++) {
            节点[i] = visit(ctx.children.get(i));
        }

        return new 编译单元(节点);
    }

    @Override
    public 抽象语法树 visitMethodDeclaration(CymbolParser.MethodDeclarationContext ctx) {

        var 返回值类型 = (类型) visitType(ctx.type());
        var 方法名称 = ctx.ID().getText();
        var 语句块 = (块语句) visitBlock(ctx.block());

        if (ctx.formalParameters() == null) {
            return new 方法定义(方法名称, 返回值类型, null, 语句块);
        }

        var 参数列表 = new 方法参数[ctx.formalParameters().type().size()];
        for (var i = 0; i < 参数列表.length; i++) {
            var 参数类型 = (类型) visitType(ctx.formalParameters().type(i));
            var 参数名称 = ctx.formalParameters().ID(i).getText();
            参数列表[i] = new 方法参数(参数类型, 参数名称);
        }
        return new 方法定义(方法名称, 返回值类型, 参数列表, 语句块);
    }

    @Override
    public 抽象语法树 visitType(CymbolParser.TypeContext ctx) {
        return new 类型(ctx.getText());
    }

    @Override
    public 抽象语法树 visitBlock(CymbolParser.BlockContext ctx) {
        if (ctx.statement() == null) {
            return new 块语句(null);
        }

        var 语句列表 = new 抽象语法树[ctx.statement().size()];
        for (var i = 0; i < 语句列表.length; i++) {
            语句列表[i] = visitStatement(ctx.statement(i));
        }

        return new 块语句(语句列表);
    }

    @Override
    public 抽象语法树 visitVarDeclaration(CymbolParser.VarDeclarationContext ctx) {
        var 类型 = (类型) visitType(ctx.type());
        var 名称 = ctx.ID().getText();
        if (ctx.expression() == null) {
            return new 变量定义语句(名称, 类型, null);
        }

        var 表达式 = (表达式) visitExpression(ctx.expression());
        return new 变量定义语句(名称, 类型, 表达式);
    }

    @Override
    public 抽象语法树 visitStatement(CymbolParser.StatementContext ctx) {
        if (ctx.block() != null) {
            return visitBlock(ctx.block());
        }

        if (ctx.varDeclaration() != null) {
            return visitVarDeclaration(ctx.varDeclaration());
        }

        if (ctx.RETURN() != null) {
            return visitExpression(ctx.expression());
        }

        if (ctx.expression() == null) {
            return visitPostfixExpression(ctx.postfixExpression());
        }

        return new 赋值语句((表达式) visitPostfixExpression(ctx.postfixExpression()), (表达式) visitExpression(ctx.expression()));
    }


    @Override
    public 抽象语法树 visitAddExpression(CymbolParser.AddExpressionContext ctx) {
        var 参数列表 = new 表达式[ctx.postfixExpression().size()];
        for (var i = 0; i < 参数列表.length; i++) {
            var 参数 = (表达式) visitPostfixExpression(ctx.postfixExpression(i));
            参数列表[i] = 参数;
        }

        return new 加法表达式(参数列表);
    }


    @Override
    public 抽象语法树 visitPostfixExpression(CymbolParser.PostfixExpressionContext ctx) {

        /*
         * 一共6种可能：
         * 1. ID                     -> 变量引用
         * 2. ID (,,...)             -> 方法调用
         *
         * 3. INT                    -> 整数字面量
         * 4. INT (,,...)            ×
         *
         * 5. (Expression)           -> 子表达式
         * 6. (Expression) (,,...)   ×
         * */

        if (ctx.primary().ID() != null) {
            var 名称 = ctx.primary().ID().getText();
            if (ctx.expressionList() != null) {
                return new 方法调用表达式(名称, (表达式列表) visitExpressionList(ctx.expressionList()));
            }

            return new 变量引用表达式(名称);
        }

        if (ctx.primary().INT() != null) {
            if (ctx.expressionList() != null) {
                throw new RuntimeException("整数字面量不支持传递参数");
            }

            return new 整数字面量表达式(Integer.parseInt(ctx.primary().INT().getText()));
        }

        if (ctx.expressionList() != null) {
            throw new RuntimeException("子表达式不支持传递参数");
        }

        return visitExpression(ctx.primary().expression());
    }

    @Override
    public 抽象语法树 visitExpressionList(CymbolParser.ExpressionListContext ctx) {
        var 表达式列表 = new 表达式[ctx.expression().size()];
        for (var i = 0; i < 表达式列表.length; i++) {
            var 表达式 = (表达式) visitExpression(ctx.expression(i));
            表达式列表[i] = 表达式;
        }

        return new 表达式列表(表达式列表);
    }
}
